package map.asteroids;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;

import fileHandling.MapLoader;
import fileHandling.SettingsLoader;

public class AsteroidGenerator {
	
	public static final String ASTEROIDS_PATH = "data/models/asteroids/";
	private static int asteroidID;	
	
	private List<String> availableAsteroids;
	private AsteroidFieldProperties properties;
	private Vector3f currentPos;
	private float currentLength, minSize, maxSize, minFieldLength, maxFieldLength, 
					minFieldWidth, maxFieldWidth, minFieldHeight, maxFieldHeight;
	private int fieldWidthDiff, fieldHeightDiff, asteroidNumber;
	private Random r;
	private String fieldPath;
	
	private AsteroidGenerator(AsteroidFieldProperties properties, String fieldPath) {
		this.properties = properties;
		this.fieldPath = fieldPath;
		
		r = new Random();
		asteroidNumber = 0;
		
		findAvailableAsteroids();
		
		minFieldLength = properties.getMinFieldLength();
		maxFieldLength = properties.getMaxFieldLength();
		assert(maxFieldLength >= minFieldLength);
		
		minFieldWidth = properties.getMinFieldWidth();
		maxFieldWidth = properties.getMaxFieldWidth();
		assert(maxFieldWidth >= minFieldWidth);
		fieldWidthDiff = (int)(maxFieldWidth - minFieldWidth);
		
		minFieldHeight = properties.getMinFieldHeight();
		maxFieldHeight = properties.getMaxFieldHeight();
		assert(maxFieldHeight >= minFieldHeight);
		fieldHeightDiff = (int)(maxFieldHeight - minFieldHeight);
		
		currentPos = properties.getStartPoint();
		minSize = properties.getMinSize();
		maxSize = properties.getMaxSize();
	}
	
	private void createAsteroids() {
		Vector3f lastXPos = currentPos.clone();
		while(currentLength < maxFieldLength) {
			
			float currentWidth = 0;
			float nextWidth = minFieldWidth + r.nextInt(fieldWidthDiff);
			Vector3f lastZPos = currentPos.clone();
			
			while(currentWidth < nextWidth) {
				
				float currentHeight = 0;
				float nextHeight = minFieldHeight + r.nextInt(fieldHeightDiff);
				
				while(currentHeight < nextHeight) {
					int nextAsteroidPath = r.nextInt(availableAsteroids.size());
					String asteroidName = availableAsteroids.get(nextAsteroidPath);
					
					AsteroidProperties props = new AsteroidProperties();
					props.setAsteroidID(asteroidID);
					props.setPosition(getDiffPos(currentPos));
					props.setScale(minSize + r.nextInt((int)(maxSize - minSize)));
					props.setModelPath(ASTEROIDS_PATH + asteroidName + "/");
					
					Quaternion rot = new Quaternion();
					Vector3f rotVector = new Vector3f(r.nextFloat(), r.nextFloat(), r.nextFloat());
					rotVector.normalizeLocal();
					float newAngle = r.nextInt(360) * FastMath.DEG_TO_RAD;
					rot.fromAngleNormalAxis(newAngle, rotVector);
					
					props.setRotation(rot);
					if(properties.isResourceField()) 
						props.setResource(getRandomResource(properties.getMinRes(), properties.getMaxRes()));
					
					String asteroidFile = fieldPath + "/asteroid" + asteroidNumber + ".xml";
					SettingsLoader.saveSettings(asteroidFile, props);
					
					currentHeight += getNextDistance(Vector3f.UNIT_Y);
					
					asteroidNumber++;
					asteroidID++;
				}
				float newWidth = getNextDistance(Vector3f.UNIT_Z);
				currentWidth += newWidth;
				lastZPos.addLocal(Vector3f.UNIT_Z.mult(newWidth));
				currentPos.set(lastZPos);
			}
			float nextLength = getNextDistance(Vector3f.UNIT_X);
			currentLength += nextLength;
			lastXPos.addLocal(Vector3f.UNIT_X.mult(nextLength));
			currentPos.set(lastXPos);
		}
		
		properties.setAsteroidAmount(asteroidNumber);
		properties.setFieldPath(fieldPath);
		SettingsLoader.saveSettings(fieldPath + "/properties.xml", properties);
	}
	
	private int getRandomResource(int minRes, int maxRes) {
		return minRes + r.nextInt(maxRes - minRes);
	}
	
	private float getNextDistance(Vector3f direction) {
		Vector3f lastPos = new Vector3f(currentPos);
		int distDiff = (int)(properties.getMaxDist() - properties.getMinDist());
		float nextDistance = properties.getMinDist() + r.nextInt(distDiff);
		currentPos.addLocal(direction.mult(nextDistance));
		return lastPos.distance(currentPos);
	}
	
	private Vector3f getDiffPos(Vector3f dir) {
		int firstFactor = (int)properties.getMinDisLoc();
		int secondFactor = (int)(properties.getMaxDisLoc() - properties.getMinDisLoc());
		int disLocX = firstFactor + r.nextInt(secondFactor) * (r.nextBoolean() ? 1 : -1);
		int disLocY = firstFactor + r.nextInt(secondFactor) * (r.nextBoolean() ? 1 : -1);
		int disLocZ = firstFactor + r.nextInt(secondFactor) * (r.nextBoolean() ? 1 : -1);
		return dir.add(disLocX, disLocY, disLocZ);
	}
	
	private void findAvailableAsteroids() {
		availableAsteroids = new ArrayList<String>();
		File asteroidsDir = new File(ASTEROIDS_PATH);
		File[] asteroidPaths = asteroidsDir.listFiles();
		for(int i = 0; i < asteroidPaths.length; i++) {
			if(asteroidPaths[i].isDirectory() && !asteroidPaths[i].getPath().contains(".")) {
				availableAsteroids.add(asteroidPaths[i].getName());
			}
		}
	}
	
	public static void main(String[] args) {
		if(args.length == 1) {
			generate(args[0]);
		} else {
			List<String> allMaps = MapLoader.findMaps();
			
			for(String mapName : allMaps) {
				generate(mapName);
			}
		}
	}
	
	private static void generate(String mapName) {
		String mapFieldsPath = MapLoader.MAPS_PATH + mapName + "/asteroidFields/";
		
		File f = new File(mapFieldsPath);
		for(File subDir : f.listFiles()) {
			if(subDir.getName().startsWith(".")) continue;
			
			String fieldPath = mapFieldsPath + subDir.getName();
			String fieldPropsPath = fieldPath + "/properties.xml";
			AsteroidFieldProperties props = MapLoader.getAsteroidField(fieldPropsPath);
			
			clearAsteroidFiles(fieldPath);
			AsteroidGenerator generator = new AsteroidGenerator(props, fieldPath);
			generator.createAsteroids();
		}
		
		asteroidID = 0;
	}
	
	private static void clearAsteroidFiles(String fieldPath) {
		try {
			File file = new File(fieldPath);
			
			for(File subFile : file.listFiles()) {
				if(subFile.getName().startsWith("asteroid")) subFile.delete();
			}
		} catch(Exception e) { e.printStackTrace(); }
	}
}